package com.right.near.common.config;

import com.right.near.common.encoder.MyPasswordEncoder;
import com.right.near.common.filter.AuthTokenFilter;
import com.right.near.common.handler.FailAuthEntryPointHandler;
import com.right.near.common.handler.PermissionDeniedHandler;
import lombok.AllArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.firewall.HttpFirewall;
import org.springframework.security.web.firewall.StrictHttpFirewall;

/**
 * Security配置
 *
 * @author: Star.zhu
 * @date: 2022/7/22
 */
@Configuration
@EnableWebSecurity
@AllArgsConstructor
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig {
    private final PermissionDeniedHandler permissionDeniedHandler;

    private final FailAuthEntryPointHandler failAuthEntryPoint;

    private final UserDetailsService userDetailsService;

    private final AuthTokenFilter authTokenFilter;

    private final AuthenticationConfiguration authenticationConfiguration;

    @Bean
    SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        // 权限不足
        http.exceptionHandling().accessDeniedHandler(permissionDeniedHandler).and()
                // 认证失败
                .exceptionHandling().authenticationEntryPoint(failAuthEntryPoint).and()
                // 关闭csrf防护
                .csrf().disable()
                // 基于token，所以不需要session
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
                // 关闭记住我
                .rememberMe().disable()
                .authorizeRequests().antMatchers("/auth/user/login").permitAll()
                .anyRequest().authenticated().and();

        // 禁用缓存
        http.headers().cacheControl();
        // 添加过滤
        http.addFilterBefore(authTokenFilter, UsernamePasswordAuthenticationFilter.class);
        return http.build();
    }

    @Autowired
    public void configureAuthentication(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
        authenticationManagerBuilder
                // 设置UserDetailsService
                .userDetailsService(userDetailsService)
                // 使用BCrypt进行密码的hash
                .passwordEncoder(new MyPasswordEncoder());
    }

    @Bean
    HttpFirewall httpFirewall() {
        StrictHttpFirewall firewall = new StrictHttpFirewall();
        firewall.setAllowUrlEncodedDoubleSlash(true);
        return firewall;
    }

    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return authenticationConfiguration.getAuthenticationManager();
    }

}
